<?php

class Kd_Data_Dcl_Query extends Kd_Data_Dcl_Base {

    protected $select = NULL;
    protected $from = NULL;
    protected $where = NULL;
    protected $join = NULL;
    protected $orderBy = NULL;
	protected $groupBy = NULL;
    protected $limit = NULL;
    protected $parameters = array();

    public function __construct() {
		$this->select()->all();
		$this->from();
    }

    public function __call($name, $arguments) {
        switch ($name) {
            case 'eq':
            case 'lt':
            case 'gt':
            case 'lteq':
            case 'gteq':
            case 'neq':
            case 'like':
            case 'contain':
            case 'not':
            case 'isNull':
            case 'orNext':
            case 'andNext':
                return call_user_func_array(array($this->where(), $name), $arguments)->closest();
            case 'field':
            case 'fields':
            case 'distinct':
                return call_user_func_array(array($this->select(), $name), $arguments)->closest();
            case 'innerJoin':
                return call_user_func_array(array($this->join(), 'innerOn'), $arguments)->closest();
            case 'leftJoin':
                return call_user_func_array(array($this->join(), 'leftOn'), $arguments)->closest();
            case 'rightJoin':
                return call_user_func_array(array($this->join(), 'rightOn'), $arguments)->closest();
            case 'asc':
                return $this->orderBy()->asc($arguments[0])->closest();
            case 'desc':
                return $this->orderBy()->desc($arguments[0])->closest();
        }
    }

    public function select() {
    	if(is_null($this->select)){
    		$this->select = new Kd_Data_Dcl_Expression_Select();
    		$this->select->setOwner($this);
    	}
        return $this->select;
    }

    public function from($table = NULL, $alias = NULL) {
    	if(is_null($this->from)){
    		$this->from = new Kd_Data_Dcl_Expression_From();
    		$this->from->setOwner($this);
    	}
    	if(!empty($table)){
    		$this->from->setName($table);
    	}
    	if(!empty($alias)){
    		$this->from->setAlias($alias);
    	}
        return $this;
    }

    public function join() {
    	if(is_null($this->join)){
    		$this->join = new Kd_Data_Dcl_Expression_Join();
    		$this->join->setOwner($this);
    	}
        return $this->join;
    }

    public function where() {
    	if(is_null($this->where)){
    		$this->where = new Kd_Data_Dcl_Expression_Where();
    		$this->where->setOwner($this);
    	}
        return $this->where;
    }

    public function orderBy() {
    	if(is_null($this->orderBy)){
    		$this->orderBy = new Kd_Data_Dcl_Expression_Orderby();
    		$this->orderBy->setOwner($this);
    	}
        return $this->orderBy;
    }

	public function groupBy(){
		if(is_null($this->groupBy)){
        	$this->groupBy = new Kd_Data_Dcl_Expression_Groupby();
        	$this->groupBy->setOwner($this);		
		}		
		$this->groupBy->setFields(func_get_args());
		return $this->groupBy;
	}    

    public function limit($count, $offset = 0) {
        $this->limit = array('count' => $count, 'offset' => $offset);
        return $this;
    }

    public function pagination($pageIndex = 1, $pageSize = 10) {
        return $this->limit($pageSize, ($pageIndex - 1) * $pageSize);
    }

    public function getSelect() {
        return $this->select;
    }

    public function getFrom() {
        return $this->from;
    }

    public function getJoin() {
        return $this->join;
    }

    public function getWhere() {
        return $this->where;
    }

    public function getOrderBy() {
        return $this->orderBy;
    }
	
	public function having($condition, $isAnd = NULL){
		if(!empty($this->having)){
			$endCond = &end($this->having);
			if(!isset($endCond['logic'])){
				$endCond['logic'] = 'and';
			}
		}
		$condition = array('condition'=>$condition);
		if(!is_null($isAnd)){
			$condition['logic'] = $isAnd? 'and': 'or';
		}
		$this->having[] = $condition;
		return $this;
	}

    public function reset() {
        return $this->resetSelect()
                ->resetFrom()
                ->resetJoin()
                ->resetWhere()
                ->resetOrderby()
                ->resetParameters()
                ->resetLimit();
    }

    public function resetSelect() {
        $this->select = NULL;
        return $this;
    }

    public function resetFrom() {
        $this->from = NULL;
        return $this;
    }

    public function resetJoin(){
        $this->join = NULL;
        return $this;
    }

    public function resetWhere() {
    	$this->where = NULL;
        return $this;
    }

    public function resetOrderby() {
    	$this->orderBy = NULL;
        return $this;
    }

    public function resetLimit() {
        $this->limit = NULL;
        return $this;
    }

    public function resetParameters() {
        $this->parameters = array();
        return $this;
    }

	public function resetGroupBy(){
		$this->groupBy = NULL;
		return $this;
	}

    public function toSql() {
        return Kd_Data_Factory::getQueryParser()->parse($this);
    }

    public function fetch() {
        $driver = $this->getDbDriver()->setSql($this->toSql(), $this->getParameters());
        return is_array($this->limit) ?
                $driver->fetchLimit($this->limit['count'], $this->limit['offset']) :
                $driver->fetch();
    }

    public function fetchCount() {
        $this->resetSelect()
        	 ->resetOrderby()
             ->select()
             ->field(Kd_Data_Dcl_Fn::count(), 'records');
        return $this->getDbDriver()->setSql($this->toSql(), $this->getParameters())->fetch()->getFirstValue();
    }
}